/* 
 * This program (together with middlebox and recv_public_trigger)
 * illustrates how a sender can use a stack of IDs to send the
 * packets through a sequence of middleboxes. 
 * Usage: 
 *   > recv_public_trigger <cfg_file.xml>
 *   > middlebox <cfg_file.xml>
 *   > ...
 *   > middlebox <cfg_file.xml>
 *   > send_middlebox <cfg_file.xml> <id1> <id2> ... <idn>
 * (id1, id2, ..., id(n-1) are the IDs of the triggers inserted by 
 *  middleboxes, and idn represents the ID of the trigger inserted
 *  by the receiver. These IDs are printed by each middlebox instance 
 *  and by recv_public_middlebox, respectively)
 *
 */

#include <stdio.h>

#include "i3.h"
#include "i3_client_api.h"
#include "utils.h"

#define TO_SEND_USEC 1000000
#define TO_SEND_SEC  0

#define PRINT_GRANULARITY 1  /* print every other PRINT GRANULARITY packet */
#define PKTS_PER_SLICE    1  /* there are 1e+6*PKTS_PER_SLICE/TO_SEND_USEC
			      * sent per second 
			      */

typedef struct {
  ID *s;
  int len;
} my_stack;

void send_data(my_stack *my_s)
{
#define MY_PKT_SIZE 1000
  static long    seq = 0;
  long           temp; 
  static cl_buf *clb = NULL;
  struct timeval tv;
  
  
  if (clb == NULL) 
    clb = cl_alloc_buf(MY_PKT_SIZE);

  temp = htonl(++seq);
  memcpy(clb->data, &temp, sizeof(long));
  clb->data_len = sizeof(long); 
  
  /* send packet */
  cl_send_stack(my_s->s, my_s->len, clb, 0);
  
  printf("sent, seq. #: %ld\n", seq);

  /* set timer to send next packet */
  tv.tv_sec  = TO_SEND_SEC;
  tv.tv_usec = TO_SEND_USEC;
  cl_set_timer(&tv, send_data, my_s);
}  

void no_matching_trigger(void *ctx_data, void *data, void *fun_ctx)
{
    ID *id = (ID *) ctx_data;
  printf("Following ID not found, ");
  print_id(id);
}

int i3_main_loop(char *cfg_file, char *str_id, int num_ids, char **str_ids)
{
  ID             id;
  struct timeval tv;
  my_stack       my_s;

  /* initialize context */
  cl_init(cfg_file);

  /* exception when matching trigger not found */
  cl_register_callback(CL_CBK_TRIGGER_NOT_FOUND, no_matching_trigger, NULL);

  /* create packet stack */
  my_s.s = create_stack(num_ids, str_ids);
  my_s.len = num_ids;
  print_stack(my_s.s, my_s.len);

  /* setup the timer to send the first packet */
  tv.tv_usec = TO_SEND_USEC;
  tv.tv_sec = TO_SEND_SEC;
  cl_set_timer(&tv, send_data, &my_s);

  /* loop forever */
  cl_loop();

  /* destroy context */
  cl_exit();
}


int main(int argc, char **argv)
{
  if (argc < 3) {
    printf("%s <cfg_file.xml> <middlebox_id1> <middlebox_id2> ... <recv_id>\n",
	   argv[0], argv[1]);
    exit(-1);
  }
  
  i3_main_loop(argv[1], argv[2], argc-2, &argv[2]);
  return -1;
}
